package com.eryos.android.cigarettecounter;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.eryos.android.cigarettecounter.io.DataExporter;
import com.eryos.android.cigarettecounter.io.DataImporter;
import com.eryos.android.cigarettecounter.io.Preferences;
import com.eryos.android.cigarettecounter.io.RestClient;
import com.eryos.android.cigarettecounter.io.RestClient.RequestMethod;
import com.eryos.android.cigarettecounter.tool.GoogleAnalyticsProvider;
import com.eryos.android.cigarettecounter.tool.LogReporterInterface;
import com.eryos.android.cigarettecounter.tool.LogReporterInterface.LogLevel;
import com.eryos.android.cigarettecounter.widget.CigaretteCounterWidger;

/**
 * Project : CigaretteCounter Author : Olivier Combe URL : http://eryos.fr/CigaretteCounter/
 * 
 * Copyright(C)2011 - Olivier Combe
 * 
 * Licensed under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * 
 * @version \$Revision.*\$
 * @author Olivier Combe
 */
public class ConfigActivity extends RootActivity {

    /** *************** UI Elements. *************** **/
    // Data part
    private Button cleanDataButton;
    private Button exportButton;
    private Button importButton;

    // Cost part
    private Spinner boxSpinner;
    private ArrayAdapter<CharSequence> adapter;
    private EditText priceInputField;

    // Widget part
    private EditText widgetLowLevelField;
    private EditText widgetHighLevelField;

    private Button validButton;
    private Button sendLogButton;

    // Market Part
    private Button checkUpdateButton;
    private TextView marketLastVersionField;
    private Button marketUpdateButton;

    /** *************** Instance Variables. *************** **/
    private int boxSize = -1;
    private float boxPrice = -1L;
    private float cigPrice = -1L;

    /* Android Market Information */
    private String marketLastVersion;
    private int marketLastVersionCode;
    private String marketPackageName;
    private String marketID;

    // Need handler for callbacks to the UI thread
    private final Handler mHandler = new Handler();

    // Create runnable for posting
    private final Runnable mCheckUpdateOk = new Runnable() {
        @Override
        public void run() {
            checkForUpdateComplete();
        }
    };

    private final Runnable mImportOk = new Runnable() {
        @Override
        public void run() {
            importDataComplete();
        }
    };

    private final Runnable mExportOk = new Runnable() {
        @Override
        public void run() {
            exportDataComplete();
        }
    };

    private final Runnable mDeleteOk = new Runnable() {
        @Override
        public void run() {
            deleteDataComplete();
        }
    };

    /** ###################################################################### **/
    /** ###################################################################### **/

    /**
     * Method used to init values(no UI component, data & default values only).
     */
    @Override
    public void initValues() {
        marketLastVersionCode = -1;
        marketLastVersion = "NA";
        marketPackageName = null;
        marketID = null;
    }

    /**
     * Method used to init UI component(no data).
     */
    @Override
    public void initUI() {
        setContentView(R.layout.config);

        // Data
        cleanDataButton = (Button) findViewById(R.id.config_data_delete_button);
        exportButton = (Button) findViewById(R.id.config_data_export_button);
        importButton = (Button) findViewById(R.id.config_data_import_button);

        // Market
        checkUpdateButton = (Button) findViewById(R.id.config_app_check_update_button);
        marketLastVersionField = (TextView) findViewById(R.id.config_app_last_version);
        marketUpdateButton = (Button) findViewById(R.id.config_app_update_button);

        // Cost
        boxSpinner = (Spinner) findViewById(R.id.config_cost_size_value);
        priceInputField = (EditText) findViewById(R.id.config_cost_price_value);
        adapter = ArrayAdapter.createFromResource(this, R.array.sizes_array, android.R.layout.simple_spinner_item);

        // Widget
        widgetLowLevelField = (EditText) findViewById(R.id.config_level_low_value);
        widgetHighLevelField = (EditText) findViewById(R.id.config_level_high_value);

        validButton = (Button) findViewById(R.id.config_cost_valid_button);
        sendLogButton = (Button) findViewById(R.id.config_app_send_log_button);

        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        boxSpinner.setAdapter(adapter);

    }

    /**
     * Method called to update UI after data initialization.
     */
    @Override
    public void updateUI() {

        loadConfig();

        validButton.requestFocus();
        validButton.bringToFront();
    }

    /**
     * Method use to call a Web Service to check if a new version of the application is available. on official Android
     * Market.
     */
    public void checkForUpdate() {

        GoogleAnalyticsProvider.trackEvent("CheckForUpdate", "");

        // Retrieve last version deployed on Android Market
        RestClient client = new RestClient("http://eryos-androidmarketinformation.appspot.com/androidmarketinformation");
        client.addParam("appli", "com.eryos.android.cigarettecounter");

        try {
            // Call WS
            client.execute(RequestMethod.GET);

            // Parse response
            String response = client.getResponse();
            if (response != null) {
                String[] responseLines = response.split("\n");
                for (String line : responseLines) {
                    String[] elements = line.split(":");
                    if (elements[0] != null && elements.length == 2 && elements[0].equalsIgnoreCase("Version")) {
                        marketLastVersion = elements[1];
                    } else if (elements[0] != null && elements.length == 2 && elements[0].equalsIgnoreCase("Package")) {
                        marketPackageName = elements[1];
                    } else if (elements[0] != null && elements.length == 2 && elements[0].equalsIgnoreCase("ID")) {
                        marketID = elements[1];
                    } else if (elements[0] != null && elements.length == 2
                            && elements[0].equalsIgnoreCase("VersionCode")) {
                        marketLastVersionCode = Integer.valueOf(elements[1]);
                    }
                }
            }
        } catch (UnknownHostException e) {
            // No Connection available
            Toast.makeText(this, "No available connection, please retry later ...", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            Log.e(getLogTag(), "initValues(Market)", e);
        }
    }

    /**
     * Called when 'Check For Update' action is complete.
     */
    public void checkForUpdateComplete() {
        /* Refresh informations from Android Market */
        marketLastVersionField.setText(marketLastVersion);
        if (marketID != null) {
            try {
                PackageInfo packageInfo = this.getPackageManager().getPackageInfo(this.getPackageName(), 0);
                int currentVersionCode = packageInfo.versionCode;

                if (currentVersionCode < marketLastVersionCode) {
                    marketUpdateButton.setEnabled(true);
                }

            } catch (NameNotFoundException e) {
                Log.e(getLogTag(), "updateUI - VersionCode", e);
            }
        }

        hideWaitingMessage();
    }

    /**
     * Used to retrieve params already defined..
     */
    public void loadConfig() {
        Log.i(getLogTag(), "Load Config");

        Preferences pref = new Preferences(getSharedPreferences(PREFS_NAME, 0));
        pref.readParamFromFile();

        // Cost Part
        boxPrice = pref.getBoxPrice();
        boxSize = pref.getBoxSize();
        // lock = pref.getLock();

        int position = 0;
        position = adapter.getPosition(String.valueOf(boxSize));

        if (boxPrice != -1L) {
            priceInputField.setText(boxPrice + "");
        }

        if (boxSize != -1 && boxSpinner != null) {
            boxSpinner.setSelection(position);
        }
        Log.d(getLogTag(), "[updateUI] Size : " + boxSize + " Position : " + position);

        int lowValue = pref.getMediumUsageLow();
        int highValue = pref.getMediumUsageHigh();

        Log.d(getLogTag(), "[updateUI] Low : " + lowValue + " High : " + highValue);

        // Widget Part
        widgetLowLevelField.setText(String.valueOf(lowValue));
        widgetHighLevelField.setText(String.valueOf(highValue));

    }

    /**
     * Save the current params values.
     */
    public void saveConfig() {
        Log.i(getLogTag(), "Save Config");

        Preferences pref = new Preferences(getSharedPreferences(PREFS_NAME, 0));

        // Cost Param
        try {
            // Retrieve Cost params
            pref.setBoxSize(boxSize);
            Float newBoxPrice = Float.valueOf(priceInputField.getText().toString());
            pref.setBoxPrice(newBoxPrice);
            cigPrice = newBoxPrice / boxSize;
            pref.setCigarettePrice(cigPrice);
            Log.d(getLogTag(), "[saveConfig] Save Config Price : " + newBoxPrice + " Size : " + boxSize
                    + "Cigarette Price: " + cigPrice);

            // Store param
            pref.storeParamToFile();

        } catch (Exception e) {
            Log.w(getLogTag(), "Save Config", e);
        }

        // Widget Param
        try {

            // Retrieve Widget params
            pref.setMediumUsageLow(Integer.valueOf(widgetLowLevelField.getText().toString()));
            pref.setMediumUsageHigh(Integer.valueOf(widgetHighLevelField.getText().toString()));

            Log.d(getLogTag(), "[saveConfig] Low " + widgetLowLevelField.getText().toString() + " High : "
                    + widgetHighLevelField.getText().toString());

            // Update widget(s)
            CigaretteCounterWidger.updateAllWidgets(this.getApplicationContext());

            // Store param
            pref.storeParamToFile();

        } catch (Exception e) {
            Log.w(getLogTag(), "Save Config", e);
        }

        hideWaitingMessage(R.string.config_valid_OK);
    }

    /**
     * Delete all data from DB.
     */
    public void deleteData() {
        Log.i(getLogTag(), "Delete All Data");
        db.deleteAll();
    }

    /**
     * Called when 'Delete Data' action is completed.
     */
    public void deleteDataComplete() {
        hideWaitingMessage(R.string.config_delete_OK);
    }

    /**
     * Export data to SD card(Public Downloads folder).
     */
    public void exportData() {
        Log.i(getLogTag(), "Export data to SD");
        GoogleAnalyticsProvider.trackEvent("ExportToSD", "");

        // Open Stream
        DataExporter export = new DataExporter(SDCARD_NAME);

        try {
            if (export.openStream()) {

                // Retrieve data from DB
                List<String> data = db.exportData();

                // Write data to file(line by line)
                for (String line : data) {
                    export.writeDataToExternalFile(line + "\n");
                }

                // Close Stream
                export.closeStream();
            }
        } catch (IOException e) {
            Log.e(getLogTag(), "Export data to SD", e);
            hideWaitingMessage(getResources().getString(R.string.config_export_NOK, SDCARD_NAME));
        }
    }

    /**
     * Called whe 'Export Data' action is completed.
     */
    public void exportDataComplete() {
        hideWaitingMessage(getResources().getString(R.string.config_export_OK, SDCARD_NAME));
    }

    /**
     * Import data from SD Card file.
     */
    public void importData() {
        Log.i(getLogTag(), "Import data from SD");
        GoogleAnalyticsProvider.trackEvent("ImportFromSD", "");

        // Open Stream
        DataImporter importer = new DataImporter(SDCARD_NAME);
        try {

            // Check is stream is OK
            if (importer.openStream()) {

                // Read data from file
                ArrayList<String> data = importer.readDataFromExternalFile();

                // Insert data into DB
                db.importData(data);

                // Close Stream
                importer.closeStream();
            }
        } catch (IOException e) {
            Log.e(getLogTag(), "importData", e);
            hideWaitingMessage(getResources().getString(R.string.config_import_NOK, SDCARD_NAME));
        }
    }

    /**
     * Called when 'Import Data' action is completed.
     */
    public void importDataComplete() {
        hideWaitingMessage(getResources().getString(R.string.config_import_OK, SDCARD_NAME));
    }

    /** ###################################################################### **/
    /** ###################################################################### **/

    /**
     * Method used to define all handlers(button, spinner, mouse, etc.).
     */
    @Override
    public void initHandlers() {

        boxSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, final long id) {
                String res = parent.getItemAtPosition(pos).toString();
                boxSize = Integer.valueOf(res);
            }

            @Override
            public void onNothingSelected(final AdapterView<?> parent) {
            }
        });

        validButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();
                saveConfig();
            }
        });

        cleanDataButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();
                Thread t = new Thread() {
                    @Override
                    public void run() {
                        // Process action
                        deleteData();

                        // Action complete, send message to end user
                        mHandler.post(mDeleteOk);
                    }
                };
                t.start();
            }
        });

        exportButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();
                Thread t = new Thread() {
                    @Override
                    public void run() {
                        // Process action
                        exportData();

                        // Action complete, send message to end user
                        mHandler.post(mExportOk);
                    }
                };
                t.start();
            }
        });

        importButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();
                Thread t = new Thread() {
                    @Override
                    public void run() {
                        // Process action
                        importData();

                        // Action complete, send message to end user
                        mHandler.post(mImportOk);
                    }
                };
                t.start();
            }
        });

        marketUpdateButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                // Link to Market :
                String uri = "http://market.android.com/details?id=" + marketPackageName;
                Log.d(getLogTag(), "uri: " + uri);
                Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
                ConfigActivity.this.startActivity(intent);
            }
        });

        checkUpdateButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();
                Thread t = new Thread() {
                    @Override
                    public void run() {
                        // Process action
                        checkForUpdate();

                        // Action complete, send message to end user
                        mHandler.post(mCheckUpdateOk);
                    }
                };
                t.start();
            }
        });

        sendLogButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(final View v) {
                showWaitingMessage();

                extractLog();

                hideWaitingMessage();
            }
        });
    }

    /**
     * Send log to dev team(// TODO).
     */
    public void extractLog() {

        GoogleAnalyticsProvider.trackEvent("Debug", "SendLog");

        LogReporterInterface logReporter = new LogReporterInterface(ConfigActivity.this);

        /* Mail config */

        logReporter.addMailRecipient(getResources().getString(R.string.config_log_mail_recipient));
        logReporter.setMailSubject(getResources().getString(R.string.config_log_mail_subject));
        logReporter.setMailMessage("Please find Log file in attachment \n\n <Your message here> \n\n");

        /* Log Config */
        logReporter.setDebugInfo("App Version :" + getString(R.string.version) + "\n" + "Build :"
                + getString(R.string.build));
        logReporter.setMaxLogLines(1500);

        /* Log Filters */
        logReporter.addLogFilter("CigaretteCounter", LogLevel.ALL);
        logReporter.addLogFilter("CigaretteDatabase", LogLevel.ALL);
        logReporter.addLogFilter("ConfigActivity", LogLevel.ALL);
        logReporter.addLogFilter("HistoryActivity", LogLevel.ALL);
        logReporter.addLogFilter("CigaretteWidget", LogLevel.ALL);
        logReporter.addLogFilter("ActivityManager", LogLevel.ALL);

        /* Extract data from logs */
        logReporter.start();
    }
}
